package models

import (
	"errors"
	"fmt"
	"github.com/spf13/cast"
	"hc_server/routers/response/transactionManagerResponse"
	"strings"
	"time"
)

type MerchantOrder struct {
	Model
	MerchantId int     `json:"merchant_id" gorm:"comment:'商户id'"`
	AgentId    int     `json:"agent_id" gorm:"comment:'所属代理商id'"`
	OrderNo    string  `json:"order_no" gorm:"comment:'订单号'"`
	Amount     float32 `json:"amount" gorm:"type:decimal(10,2);comment:'交易金额，单位为元，保留两位小数，取值范围[0.01,100000000]'"`
	Subject    string  `json:"subject" gorm:"comment:'订单标题'"`
	Body       string  `json:"body" gorm:"comment:'订单描述'"`
	Platform   int     `json:"platform" gorm:"comment:'交易通道:1=联动'"`
	DeviceId   int     `json:"device_id" gorm:"comment:'设备id'"`
	PayType    int     `json:"pay_type" gorm:"comment:'支付方式:1-微信；2-支付宝；3-云闪付；5-聚分期；'"`
	PayRate    float32 `json:"pay_rate" gorm:"type:decimal(10,6);comment:'支付费率'"`
	PayInfo    string  `json:"pay_info" gorm:"comment:'支付当时此商户的各级代理商与各级费率json，'"`
	Type       int     `json:"type" gorm:"comment:'1=下单成功 2=支付成功 3=支付失败'"`
	Request    string  `json:"request" gorm:"comment:'请求支付通道的参数json'"`
	Response   string  `json:"response" gorm:"comment:'支付通道返回的参数json'"`
	Callback   string  `json:"callback" gorm:"comment:'支付通道回调我们接口的数据'"`
}

// MerchantOrderAdd 添加订单
func MerchantOrderAdd(order *MerchantOrder) *MerchantOrder {
	db.Create(&order)
	return order
}

// MerchantOrderIsExist 判断订单是否存在
func MerchantOrderIsExist(ids string) bool {
	var count int64
	db.Model(&MerchantOrder{}).Where("FIND_IN_SET(id, ?)", ids).Count(&count)
	return cast.ToInt(count) == strings.Count(ids, ",")+1 // 加上 1 是因为本身的字符串
}

// MerchantOrderUpdate 更新订单
func MerchantOrderUpdate(mapd map[string]interface{}, orderNo interface{}) (*MerchantOrder, error) {
	var temp *MerchantOrder
	db.Model(&MerchantOrder{}).Where("order_no = ?", orderNo).Scan(&temp)
	if temp.ID == 0 {
		return nil, errors.New("订单更新失败")
	}
	db.Model(&MerchantOrder{}).Where("order_no = ?", orderNo).Updates(mapd)
	return temp, nil
}

// TransactionManagerTransactionInfo 交易详细
func TransactionManagerTransactionInfo(id int) (*transactionManagerResponse.TransactionManagerTransactionInfoResponse, error) {
	var info *transactionManagerResponse.TransactionManagerTransactionInfoResponse
	db.Model(&MerchantOrder{}).Select(""+
		"merchant_orders.id,merchant_orders.amount,merchants.merchant_name AS name,"+
		"CONCAT('M',merchants.merchant_no) AS merchant_no,device_types.name AS device_type,device_models.device_no AS device_code,"+
		"merchant_orders.created_at AS time,merchant_orders.pay_type,merchant_orders.order_no").
		Joins("LEFT JOIN merchants ON merchants.id = merchant_orders.merchant_id").
		Joins("LEFT JOIN devices ON devices.id = merchant_orders.device_id").
		Joins("LEFT JOIN device_models ON device_models.id = devices.device_model_id").
		Joins("LEFT JOIN device_types ON device_types.id = device_models.device_type_id").
		Where("merchant_orders.id= ?", id).Scan(&info)
	if cast.ToInt(info.Id) == 0 {
		return nil, errors.New("订单不存在")
	}
	return info, nil
}

// GetTransactionDayInfo 获取交易统计
func GetTransactionDayInfo(agentId int) (*transactionManagerResponse.GetTransactionDayInfo, error) {
	var info *transactionManagerResponse.GetTransactionDayInfo
	result := db.Raw(` SELECT  
            COALESCE(SUM(merchant_orders.amount), 0) AS amount,  
            COUNT(merchant_orders.id) AS pay_num,  
            (SELECT COUNT( merchant.id ) FROM merchant_relations AS merchant WHERE FIND_IN_SET( ?, merchant.relation )) AS merchant_num,  
            (SELECT COUNT(DISTINCT devices.id ) FROM merchant_relations AS dev LEFT JOIN devices ON dev.merchant_id = devices.merchant_id WHERE FIND_IN_SET( ?, dev.relation )) AS device_num  
            FROM merchant_relations INNER JOIN merchant_orders ON merchant_relations.merchant_id = merchant_orders.merchant_id    
            WHERE FIND_IN_SET( ?, merchant_relations.relation ) > 0   AND merchant_orders.deleted_at IS NULL`, agentId, agentId, agentId).Scan(&info)

	if result.Error != nil {
		return nil, errors.New("获取失败")
	}

	return info, nil
}

// GetTransactionTimeTypeInfo 按时间查询交易统计
func GetTransactionTimeTypeInfo(agentId, timeStr interface{}) (*transactionManagerResponse.GetTransactionDayInfo, error) {
	var info *transactionManagerResponse.GetTransactionDayInfo
	db.Model(&MerchantRelation{}).Select("COALESCE ( SUM( merchant_orders.amount ), 0 ) AS amount,"+
		"COUNT( merchant_orders.id ) AS pay_num,"+
		"COUNT(merchants.id) AS merchant_num,"+
		"COUNT(devices.id) AS device_num").
		Joins(`LEFT JOIN merchants ON merchants.id = merchant_relations.merchant_id AND merchants.`+cast.ToString(timeStr)).
		Joins(`LEFT JOIN merchant_orders ON merchant_orders.merchant_id = merchant_relations.merchant_id AND merchant_orders.`+cast.ToString(timeStr)).
		Joins(`LEFT JOIN devices ON devices.merchant_id = merchant_orders.merchant_id AND devices.`+cast.ToString(timeStr)).
		Where("FIND_IN_SET( ?, merchant_relations.relation ) ", agentId).Scan(&info)

	return info, nil
}

func GetIncomeInfo(timeSql, timeStr string, agentId int) (any, error) {
	var info *transactionManagerResponse.GetIncomeInfo
	db.Model(&AgentRelation{}).Select("(COALESCE( SUM(agent_income_logs.amount ), 0) ) AS income").
		Joins(`LEFT JOIN agent_income_logs ON agent_income_logs.agent_id = agent_relations.agent_id AND agent_income_logs.`+timeSql).
		Where("FIND_IN_SET( ?, agent_relations.relation )", agentId).Scan(&info)
	info.Time = timeStr

	return info, nil
}

// GetMerchantIncomeList 获取收益列表
func GetMerchantIncomeList(agentId, pageNum, pageSize int) (any, error) {
	pageNum--
	start := time.Now().AddDate(0, 0, -pageNum*pageSize-pageSize).Format("2006-01-02")
	end := time.Now().AddDate(0, 0, -pageNum*pageSize+1).Format("2006-01-02")

	var info = make([]*transactionManagerResponse.GetMerchantIncomeList, 0)
	db.Model(&AgentRelation{}).Select("DATE_FORMAT( agent_income_logs.created_at, '%Y-%m-%d' ) AS date,"+
		"COALESCE (SUM(CASE WHEN agent_income_logs.agent_id = ? THEN agent_income_logs.amount ELSE 0 END), 0 ) AS profit,"+
		"COALESCE (SUM(CASE WHEN agent_income_logs.agent_id <> ? THEN agent_income_logs.amount ELSE 0 END), 0 ) AS subordinate_profit,"+
		"COALESCE (SUM(CASE WHEN agent_income_logs.agent_id = ? THEN agent_income_logs.amount ELSE 0 END) + SUM(CASE WHEN agent_income_logs.agent_id <> ? THEN agent_income_logs.amount ELSE 0 END), 0 ) AS total_profit", agentId, agentId, agentId, agentId).
		Joins("LEFT JOIN agent_income_logs ON agent_income_logs.agent_id = agent_relations.agent_id").
		Where("FIND_IN_SET( ?, agent_relations.relation ) AND agent_income_logs.created_at BETWEEN '"+start+"' AND '"+end+"'", agentId).
		Group("DATE_FORMAT( agent_income_logs.created_at, '%Y-%m-%d' )").Scan(&info)

	var count int64
	db.Model(&AgentRelation{}).Select("COUNT(DISTINCT DATE_FORMAT(agent_income_logs.created_at,'%Y-%m-%d'))").
		InnerJoins("INNER JOIN agent_income_logs ON agent_income_logs.agent_id = agent_relations.agent_id ").
		Where("FIND_IN_SET( ?, agent_relations.relation )", agentId).Scan(&count)

	return map[string]interface{}{
		"list":  info,
		"count": count,
	}, nil
}

// GetMerchantIncomeDateList 获取商户收入列表
func GetMerchantIncomeDateList(time string, agentId int) (any, error) {
	var result = make([]*transactionManagerResponse.GetMerchantIncomeDateList, 0)
	db.Model(&MerchantRelation{}).Select("merchant_orders.id,"+
		"merchants.merchant_name AS title,merchant_orders.pay_type AS type,merchant_orders.amount,merchant_orders.created_at AS time,"+
		"COALESCE (SUM(CASE WHEN agent_income_logs.agent_id = ? THEN agent_income_logs.amount ELSE 0 END), 0 ) AS profit,"+
		"COALESCE (SUM(CASE WHEN agent_income_logs.agent_id = ? THEN agent_income_logs.amount ELSE 0 END) + SUM(CASE WHEN agent_income_logs.agent_id <> ? THEN agent_income_logs.amount ELSE 0 END), 0 ) AS total_profit", agentId, agentId, agentId).
		InnerJoins("INNER JOIN merchant_orders ON merchant_orders.merchant_id = merchant_relations.merchant_id").
		InnerJoins("INNER JOIN merchants ON merchant_orders.merchant_id = merchants.id").
		InnerJoins("INNER JOIN agent_income_logs ON agent_income_logs.agent_id = merchant_relations.agent_id").
		Where("FIND_IN_SET(?,merchant_relations.agent_id) AND DATE(merchant_orders.created_at) = ? AND DATE(agent_income_logs.created_at) = ?", agentId, time, time).
		Group("merchant_orders.id").Scan(&result)

	var count int64
	db.Model(&MerchantRelation{}).Select("COUNT(merchant_orders.id)").
		InnerJoins("INNER JOIN merchant_orders ON merchant_orders.merchant_id = merchant_relations.merchant_id").
		Where("FIND_IN_SET(?,merchant_relations.agent_id) AND DATE(merchant_orders.created_at) = ?", agentId, time).Scan(&count)
	return map[string]interface{}{
		"list":  result,
		"count": count,
	}, nil
}

// GetMerchantIncomeDateInfo 收益商户订单详细
func GetMerchantIncomeDateInfo(agentId, orderId int) (any, error) {
	var result *transactionManagerResponse.GetMerchantIncomeDateInfo
	db.Model(&MerchantOrder{}).Select("merchant_orders.id,"+
		"(CASE "+
		"WHEN merchant_orders.pay_type = 1 THEN agent_rates.wechat_min "+
		"WHEN merchant_orders.pay_type = 2 THEN agent_rates.alipay_min "+
		"WHEN merchant_orders.pay_type = 3 AND merchant_orders.amount <= 1000 THEN agent_rates.yun_pay_low_min "+
		"WHEN merchant_orders.pay_type = 3 AND merchant_orders.amount > 1000 THEN agent_rates.yun_pay_high_min "+
		"END) AS cost,activities.name AS activity,merchant_orders.order_no,CONCAT('M',merchants.merchant_no) AS merchant_no,"+
		"merchant_orders.pay_type AS type,merchant_orders.amount,merchant_orders.pay_rate AS rate,sub_agents.agent_name AS subordinate_agent,"+
		"agents.agent_name AS agent,salesmens.name AS salesman,"+
		"COALESCE ((SELECT SUM(amount) FROM agent_income_logs WHERE order_id = ? AND agent_id = ?), 0 ) AS profit,"+
		"COALESCE ((SELECT SUM(amount) FROM agent_income_logs WHERE order_id = ? AND agent_id <> ?), 0 ) AS subordinate_profit", orderId, agentId, orderId, agentId).
		Joins("LEFT JOIN agent_rates ON agent_rates.agent_id = merchant_orders.agent_id").
		Joins("LEFT JOIN merchants ON merchants.id = merchant_orders.merchant_id").
		Joins("LEFT JOIN activities ON activities.id = merchants.activity_id").
		Joins("LEFT JOIN agent_relations ON agent_relations.agent_id = merchant_orders.agent_id").
		Joins("LEFT JOIN agents AS sub_agents ON sub_agents.id = agent_relations.base_agent_id").
		Joins("LEFT JOIN agents ON agents.id = merchant_orders.agent_id").
		Joins("LEFT JOIN salesmens ON salesmens.id = merchants.salesmen_id").
		Where("merchant_orders.id = ?", orderId).
		Scan(&result)

	if cast.ToInt(result.Id) == 0 {
		return nil, errors.New("订单信息不存在")
	}

	result.TotalProfit = cast.ToString(fmt.Sprintf("%.2f", cast.ToFloat64(result.Profit)+cast.ToFloat64(result.SubordinateProfit)))
	result.SubordinateProfit = cast.ToString(fmt.Sprintf("%.2f", cast.ToFloat64(result.SubordinateProfit)))
	result.Profit = cast.ToString(fmt.Sprintf("%.2f", cast.ToFloat64(result.Profit)))
	result.Cost = fmt.Sprintf("%.2f", cast.ToFloat64(result.Cost))

	return result, nil
}

// WalletList 钱包详细列表
func WalletList(agentId, pageNum, pageSize int) (any, error) {
	var result = make([]*transactionManagerResponse.GetMerchantIncomeDateList, 0)
	db.Model(&MerchantRelation{}).Select("merchant_orders.id,"+
		"merchants.merchant_name AS title,merchant_orders.pay_type AS type,merchant_orders.amount,merchant_orders.created_at AS time,"+
		"COALESCE ((SELECT SUM(amount) FROM agent_income_logs WHERE order_id = merchant_orders.id AND agent_id = ?), 0 ) AS profit,"+
		"COALESCE ((SELECT SUM(agent_income_logs.amount) FROM agent_relations LEFT JOIN agent_income_logs ON agent_income_logs.agent_id = agent_relations.agent_id AND agent_income_logs.agent_id <> ? AND agent_income_logs.order_id = merchant_orders.id WHERE FIND_IN_SET(?,agent_relations.relation)), 0 ) AS subordinate_profit,"+
		"merchant_orders.pay_rate AS rate", agentId, agentId, agentId).
		InnerJoins("INNER JOIN merchant_orders ON merchant_orders.merchant_id = merchant_relations.merchant_id").
		InnerJoins("INNER JOIN merchants ON merchant_orders.merchant_id = merchants.id").
		Joins("LEFT JOIN agent_rates ON agent_rates.agent_id = ?", agentId).
		Joins("LEFT JOIN merchant_rates ON merchant_rates.merchant_id = merchant_orders.merchant_id").
		Where("FIND_IN_SET(?,merchant_relations.relation)", agentId).Group("merchant_orders.id").
		Limit(cast.ToInt(pageSize)).
		Offset((cast.ToInt(pageNum) - 1) * cast.ToInt(pageSize)).
		Scan(&result)

	var count int64
	db.Model(&MerchantRelation{}).Select("COUNT(merchant_orders.id)").
		InnerJoins("INNER JOIN merchant_orders ON merchant_orders.merchant_id = merchant_relations.merchant_id").
		Where("FIND_IN_SET(?,merchant_relations.agent_id)", agentId).Scan(&count)
	return map[string]interface{}{
		"list":  result,
		"count": count,
	}, nil
}

// WalletApplyList 申请提现列表
func WalletApplyList(agentId int) (any, error) {
	var bankInfo map[string]any
	db.Model(&AgentSettlementBank{}).
		Select("lian_bank_codes.base_name AS bank_name,RIGHT(agent_settlement_banks.no, 4) AS no").
		Joins("LEFT JOIN lian_bank_codes ON agent_settlement_banks.bank_id = lian_bank_codes.id").
		Where("agent_settlement_banks.agent_id = ?", agentId).Scan(&bankInfo)

	var orders = make([]*AgentApplyWithdrawalCache, 0)
	db.Model(&AgentRelation{}).Select("DATE_FORMAT( agent_income_logs.created_at, '%Y-%m' ) AS month,"+
		"COALESCE(SUM(CASE WHEN agent_income_logs.agent_id = ? THEN agent_income_logs.amount ELSE 0 END), 0 ) AS before_amount,"+
		"(COALESCE(SUM(CASE WHEN agent_income_logs.agent_id = ? THEN agent_income_logs.amount ELSE 0 END), 0) * 0.09) AS tax_amount,"+ // 计算上税金额
		"(COALESCE(SUM(CASE WHEN agent_income_logs.agent_id = ? THEN agent_income_logs.amount ELSE 0 END), 0) * (1 - 0.09)) AS after_amount,"+
		"GROUP_CONCAT(agent_income_logs.id SEPARATOR ',') AS order_ids", agentId, agentId, agentId).
		InnerJoins("INNER JOIN agent_income_logs ON agent_income_logs.agent_id = agent_relations.agent_id").
		Where("FIND_IN_SET( ?, agent_relations.relation )", agentId).
		Group("DATE_FORMAT( agent_income_logs.created_at, '%Y-%m' )").Scan(&orders)

	var count int64
	db.Model(&AgentRelation{}).Select("COUNT(DISTINCT DATE_FORMAT(agent_income_logs.created_at,'%Y-%m-%d'))").
		InnerJoins("INNER JOIN agent_income_logs ON agent_income_logs.agent_id = agent_relations.agent_id ").
		Where("FIND_IN_SET( ?, agent_relations.relation )", agentId).Scan(&count)

	var temps = make([]*AgentApplyWithdrawalCache, 0)
	for _, order := range orders {
		temp, err := AgentApplyWithdrawalCacheCreate(&AgentApplyWithdrawalCache{
			AgentId:      agentId,
			Month:        order.Month,
			BeforeAmount: cast.ToFloat32(order.BeforeAmount),
			TaxAmount:    cast.ToFloat32(order.TaxAmount),
			AfterAmount:  cast.ToFloat32(order.AfterAmount),
			OrderIds:     order.OrderIds,
		})

		if err != nil {
			return nil, err
		}
		temps = append(temps, temp)
	}

	return map[string]interface{}{
		"list":  temps,
		"count": count,
		"no":    bankInfo["no"],
		"name":  bankInfo["bank_name"],
	}, nil
}
